# 策略： 连续5比Tick上涨买入，连续5比Tick下跌卖出
import talib

from vnctptdType661 import *
from PyQt5 import QtWidgets, QtCore
import pandas as pd
import talib as ta
# CTP行情库
from vnctpmd import *
import globalvar
import numpy as np
import threading
from threading import Thread
class Strategy(object):
    '''    
    def __init__(self,signal_md_tick):
        self.signal_md_tick = signal_md_tick
        currpath = os.path.abspath(os.path.dirname(__file__))
        self.vnmd = CDLL(currpath + '\\vnctpmd.dll')
    '''
    def __init__(self,period):
        self.period = period
        self.dict_strategyinstrument = {}
        self.dick_tick = {}
        self.list_tick=[]
        self.fee = 0
        self.buyposition = 0
        self.sellposition = 0
        self.amount = 50000
        self.fee = 0

    def InsertOrder(self, InstrumentID , exchangeid, direction, offside, VN_OPT_LimitPrice,  price  , vol):
        if self.type==1:
            #实盘
            globalvar.td.InsertOrder(InstrumentID , exchangeid, direction, offside,VN_OPT_LimitPrice, price, vol)
        elif self.type==2:
            #Python回测
            self.InsertOrder(InstrumentID , exchangeid, direction, offside,VN_OPT_LimitPrice, price, vol)
            pass

    def checkinstrumentID(self,marketdata, strategyname):
        if strategyname in globalvar.dict_strategyinstrument:
            if str(marketdata.InstrumentID, encoding="utf-8") in globalvar.dict_strategyinstrument[strategyname]:
                return 0
            else:
                return 1
        else:
            return 1



dict_period = {'M1': '1min', 'M3': '3min',
               'M5': '5min', 'M10': '10min',
               'M15': '15min', 'M30': '30min',
               'M60': '60min', 'M120': '120min',
               'D1': '1d'
               }
class MyStrategy(Strategy, QtCore.QThread):
    def __init__(self, period):
        super(Strategy, self).__init__()
        self.period = period
        self.klinelist = []

    def OnKline(self,mddata,arg,strategyname):
        #TradingDay = klinedata.TradingDay.decode()
        #klinetime = klinedata.klinetime.decode()
        InstrumentID = mddata.InstrumentID.decode()
        exchange=mddata.exchange.decode()
        self.klinelist.append(float(mddata.close))
        try:
            float_data = [float(x) for x in self.klinelist]
        except Exception as e:
            pass
        print('结果0:' + str(float_data))

        MA3 = talib.MA(np.array(float_data), 3)

        MA5 = talib.MA(np.array(float_data), 5)

        if MA3[len(MA3)-1]>MA5[len(MA3)-1]:
            result1 = globalvar.td.InsertOrder(InstrumentID, exchange, '0', '0',VN_OPT_LimitPrice, mddata.LastPrice + 10, 1)
        elif MA3[len(MA3)-1]<MA5[len(MA3)-1]:
            result2 = globalvar.td.InsertOrder(InstrumentID, exchange, '1', '0',VN_OPT_LimitPrice, mddata.LastPrice + 10, 1)

        print('结果1:' + str(MA3))
        print('结果2:' + str(MA5))

        return [1,1]




        # 初始化该合约DataFrame类型的除M1周期以外所有周期的K线数据变量
        '''
        self.InitKlineDataFrame(InstrumentID)
        dict_period_dataframe_kline = {'K线周期: M1': globalvar.dict_dataframe_kline_M1[InstrumentID],
                                       'K线周期: M3': globalvar.dict_dataframe_kline_M3[InstrumentID],
                                       'K线周期: M5': globalvar.dict_dataframe_kline_M5[InstrumentID],
                                       'K线周期: M10': globalvar.dict_dataframe_kline_M10[InstrumentID],
                                       'K线周期: M15': globalvar.dict_dataframe_kline_M15[InstrumentID],
                                       'K线周期: M30': globalvar.dict_dataframe_kline_M30[InstrumentID],
                                       'K线周期: M60': globalvar.dict_dataframe_kline_M60[InstrumentID],
                                       'K线周期: M120': globalvar.dict_dataframe_kline_M120[InstrumentID],
                                       'K线周期: D1': globalvar.dict_dataframe_kline_D1[InstrumentID]
                                       }
        '''

        try:

            if not os.path.exists(("dataframe_kline\\" + InstrumentID)):
                os.mkdir("dataframe_kline\\" + InstrumentID)
            globalvar.dict_dataframe_kline_M1[InstrumentID].to_csv(
                "dataframe_kline\\" + InstrumentID + "\\kline_1min.csv", index=False)
            data = pd.read_csv("dataframe_kline\\" + InstrumentID + "\\kline_1min.csv", index_col='datetime',
                               parse_dates=True)

            grouper = data.groupby(
                [pd.Grouper(freq=dict_period[period]), 'recordid', 'tradingday', 'klinetime', 'instrumentid', 'open', 'close',
                 'low', 'high',
                 'vol'])

            df = pd.DataFrame(grouper['instrumentid'].count())
            df.rename(columns={'instrumentid': 'count'}, inplace=True)
            df.reset_index(inplace=True)
            del df['count']

            df2 = pd.DataFrame(
                {"datetime": [], 'recordid': [], 'tradingday': [], 'klinetime': [], 'instrumentid': [], 'open': [],
                 'close': [],
                 'low': [], 'high': [],
                 'vol': []}, index=[])

            lastdatetime = ""
            high = 0
            low = 0
            open = 0
            close = 0
            vol = 0
            instrumentid = ""
            datetime = ""
            tradingday = ""
            klinetime = ""
            recordid = 1

            for index, row in df.iterrows():
                #QApplication.processEvents()
                if lastdatetime != str(row['datetime']):
                    if open > 0:
                        tempdata = {"datetime": datetime, "recordid": '{:0>8s}'.format(str(recordid)),
                                    "tradingday": tradingday, "klinetime": klinetime,
                                    "instrumentid": instrumentid,
                                    "open": open, "close": close, "low": low, "high": high, "vol": vol}
                        df2 = df2.append(tempdata, ignore_index=True)
                    recordid = int(row['recordid'])
                    open = float(row['open'])
                    low = float(row['low'])
                    high = float(row['high'])
                    close = float(row['close'])
                    vol = int(row['vol'])
                    lastdatetime = str(row['datetime'])
                    lastclose = row['close']
                    datetime = row['datetime']
                    instrumentid = row['instrumentid']
                    tradingday = row['tradingday']
                    klinetime = row['klinetime']
                else:
                    recordid = int(row['recordid'])
                    low = min(low, float(row['low']))
                    high = max(high, float(row['high']))
                    close = float(row['close'])
                    vol = vol + int(row['vol'])

            df2 = df2.sort_values(by='recordid')
            df2.to_csv("dataframe_kline\\" + InstrumentID + "\\kline_" + period_type + ".csv", index=True)
            dict_period_dataframe_kline[period_type] = df2.copy()

            # TALIB公式计算
            '''
            dw = pd.DataFrame()
            # KDJ 值对应的函数是 STOCH
            dw['slowk'], dw['slowd'] = ta.STOCH(df2['high'].values,
                                                df2['low'].values,
                                                df2['close'].values,
                                                fastk_period=9,
                                                slowk_period=3,
                                                slowk_matype=0,
                                                slowd_period=3,
                                                slowd_matype=0)

            # 求出J值，J = (3*K)-(2*D)
            dw['slowj'] = list(map(lambda x, y: 3 * x - 2 * y, dw['slowk'], dw['slowd']))
            dw.index = range(len(dw))
            print("talib: " + dw[-3:])
            '''
            # 从内存获取K线数据并更新K线图表

            self.GetKlineFromeMemory(dict_period_dataframe_kline[period_type], period_type)

        except Exception as e:
            print("combineklineUpdateCharts Error:" + repr(e))


        dw = pd.DataFrame()
        # KDJ 值对应的函数是 STOCH
        dw['slowk'], dw['slowd'] = ta.STOCH(df2['high'].values,
                                            df2['low'].values,
                                            df2['close'].values,
                                            fastk_period=9,
                                            slowk_period=3,
                                            slowk_matype=0,
                                            slowd_period=3,
                                            slowd_matype=0)

        # 求出J值，J = (3*K)-(2*D)
        dw['slowj'] = list(map(lambda x, y: 3 * x - 2 * y, dw['slowk'], dw['slowd']))
        dw.index = range(len(dw))
        print("talib: " + dw[-3:])


        print(str(klinedata.InstrumentID))
        print(str(arg))
        self.list_tick.append(klinedata.LastPrice)

        directionnum = 0
        for i in range(arg[0]):
            if self.list_tick[i]>self.list_tick[i+1]:
                directionnum = directionnum + 1
            elif self.list_tick[i]<self.list_tick[i+1]:
                directionnum = directionnum - 1

        if directionnum == arg[0]:
            return [1,1]
        else:
            return [-1,-1]

        return [1,1]
        print('T1')
        #print(__name__)  strategyfile000.3tick
        print('T2')
        print(marketdata.InstrumentID)
        print('T21')
        print(str(arg))
        print('T22')
        print(str(marketdata.InstrumentID, encoding="utf-8"))
        print('T23')
        print('合约' + str(marketdata.InstrumentID, encoding="utf-8") + '在策略' + strategyname + '生效')
        print('T3')

        # 检查是否是本策略选中需要交易的合约编码，如果不在则返回，配置在策略文件名称一致的csv文件中，本策略是strategy1.csv，
        if self.checkinstrumentID(marketdata, strategyname):
            return
        print('T4')

        if marketdata.InstrumentID in self.dick_tick:
            pass
        else:
            list_tick = []
            self.dick_tick[marketdata.InstrumentID] = list_tick
            print(str(marketdata.InstrumentID, encoding="utf-8"))
        print('T5')

        self.dick_tick[marketdata.InstrumentID].insert(0, marketdata.LastPrice)
        print('T6')

        if len(self.dick_tick[marketdata.InstrumentID]) > 5:
            print('运行策略(' + strategyname + '.py)： ' + str(marketdata.InstrumentID, encoding="utf-8") + ',' + str(
                marketdata.LastPrice))
            print("比较" + str(marketdata.InstrumentID, encoding="utf-8") + ',' + str(
                self.dick_tick[marketdata.InstrumentID][0]) + ',' +
                  str(self.dick_tick[marketdata.InstrumentID][1]) + ',' + str(self.dick_tick[marketdata.InstrumentID][2]))
            if self.dick_tick[marketdata.InstrumentID][4] > 1e-7 and self.dick_tick[marketdata.InstrumentID][0] > \
                    self.dick_tick[marketdata.InstrumentID][1] and self.dick_tick[marketdata.InstrumentID][1] > \
                    self.dick_tick[marketdata.InstrumentID][2] and self.dick_tick[marketdata.InstrumentID][2] > \
                    self.dick_tick[marketdata.InstrumentID][3] and self.dick_tick[marketdata.InstrumentID][3] > \
                    self.dick_tick[marketdata.InstrumentID][4]:
                print("买入" + str(marketdata.InstrumentID, encoding="utf-8"))
                # 策略池功能完善中
                # 用限价单 VN_OPT_LimitPrice 方式报单 。通常用涨停价限价单模拟市价，因为市价指令不支持所有的交易所
                exchangeid = globalvar.dict_exchange[str(marketdata.InstrumentID, encoding="utf-8")].split(',')[0]

                result = globalvar.td.InsertOrder(str(marketdata.InstrumentID, encoding="utf-8"), exchangeid, '0', '1',
                                                  VN_OPT_LimitPrice, marketdata.LastPrice + 10, 1)
                result = result + globalvar.td.InsertOrder(str(marketdata.InstrumentID, encoding="utf-8"), exchangeid,
                                                           '0', '0', VN_OPT_LimitPrice, marketdata.LastPrice + 10, 1)
                if result == 0:
                    print('报单成功')
                else:
                    print('报单失败')

            elif self.dick_tick[marketdata.InstrumentID][4] > 1e-7 and self.dick_tick[marketdata.InstrumentID][0] < \
                    self.dick_tick[marketdata.InstrumentID][1] and self.dick_tick[marketdata.InstrumentID][1] < \
                    self.dick_tick[marketdata.InstrumentID][2] and self.dick_tick[marketdata.InstrumentID][2] < \
                    self.dick_tick[marketdata.InstrumentID][3] and self.dick_tick[marketdata.InstrumentID][3] < \
                    self.dick_tick[marketdata.InstrumentID][4]:
                print("卖出" + str(marketdata.InstrumentID, encoding="utf-8"))
                # 策略池功能完善中
                # 用限价单 VN_OPT_LimitPrice 方式报单 。通常用涨停价限价单模拟市价，因为市价指令不支持所有的交易所
                exchangeid = globalvar.dict_exchange[str(marketdata.InstrumentID, encoding="utf-8")].split(',')[0]
                result = globalvar.td.InsertOrder(str(marketdata.InstrumentID, encoding="utf-8"), exchangeid, '1', '1',
                                                  VN_OPT_LimitPrice, marketdata.LastPrice - 10, 1)
                result = result + globalvar.td.InsertOrder(str(marketdata.InstrumentID, encoding="utf-8"), exchangeid,
                                                           '1', '0', VN_OPT_LimitPrice, marketdata.LastPrice - 10, 1)
                if result == 0:
                    print('报单成功')
                else:
                    print('报单失败')
